﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using Stamp_For_Africa_Version_2.Models;
using Stamp_For_Africa_Version_2.Repositories;

namespace Stamp_For_Africa_Version_2.Helpers
{
	
	public class TextSearcher
	{

		public String CountryName { get; set; }
		public String ArtistName { get; set; }
		public List<String> Categories { get; set; }
		
		public String FaceValue { get; set; }
		public List<String> Colours { get; set; }
		public List<String> Dates { get; set; }
		public List<String> WildCards { get; set; } 
		public bool IsMajorCurrency { get; set; }
		public String OriginalSearchText { get; set; }
		public List<SearchHit> HitList { get; set; } 

		private bool _isMajor;


		public static String StripArticlesFromSearchString(String searchString)
		{
			//And
			String returnString = searchString.ToLower().Replace(" and ", " ");
			//Or
			returnString = returnString.Replace(" or ", " ");
			//At
			returnString = returnString.Replace(" a t", " ");

			return returnString;
		}

		public static List<String> ExtractStampYearFromSearchString(ref String searchString)
		{
			string pattern = "(?<Year>(?:\\d{4}))";

			bool carryon = true;
			List<String> dates = new List<string>();

			while (true)
			{
				Match regMatch = Regex.Match(searchString, pattern);
				if (String.IsNullOrEmpty(regMatch.Value))
					break;

				dates.Add(regMatch.Value);
				searchString = searchString.Replace(regMatch.Value, "");
			}

			return dates;
		}


		/* ==========================================================
		 *	REG EX CURRENCY EXPRESSIONS
		 *	
		 * US. Dollar with leading $ in front :	^\$?([0-9]{1,3},([0-9]{3},)*[0-9]{3}|[0-9]+)(\.[0-9][0-9])?$
		 * ZAR Rand with leaving R/r in front : "^R?([0-9]{1,3},([0-9]{3},)*[0-9]{3}|[0-9]+)(\.[0-9][0-9])?$"
		 * Any Cent (trailing c) behind : [0-9]c$
		 *	*/

		public static String ExtractStampValueFromSearchString(ref String searchString, ref bool major)
		{

			//First check for minor symbos, these include "cents etc"
			String minorPattern = "[0-9]{1,3}c|[0-9]{1,3}p|[0-9]{1,3}c|[0-9]{1,3}d";
			String majorPattern = "[a-z][0-9]{1,3}";
			String justValue = "[0-9]{1,3}";
			Match regMatch = Regex.Match(searchString, minorPattern);

			if (!String.IsNullOrEmpty(regMatch.Value))
			{
				major = false;
				searchString = searchString.Replace(regMatch.Value, "");
				
				String fullValue = regMatch.Value;
				regMatch = Regex.Match(fullValue, justValue);

				return regMatch.Value;
			}
			else
			{
								
				regMatch = Regex.Match(searchString, majorPattern);
				
				if (!String.IsNullOrEmpty(regMatch.Value))
				{
					major = true;
					searchString = searchString.Replace(regMatch.Value, "");

					String fullValue = regMatch.Value;
					regMatch = Regex.Match(fullValue, justValue);

					return regMatch.Value;
				}

			}

			return "";
		}


		public static String ExtractCountryFromSearchString(ref String searchString)
		{

			CountryRepository countryRepository = new CountryRepository();
			List<String> fullCountryNames = countryRepository.FindAllCountries().Select(u => u.Name.ToLower()).ToList();
			List<String> abrvCountryNames = countryRepository.FindAllCountries().Select(u => u.Abbreviation.ToLower()).ToList();

			foreach (var countryName in fullCountryNames)
			{
				if (searchString.Contains(countryName))
				{
					searchString = searchString.Replace(countryName, "");
					return countryName;
				}
			}


			foreach (var countryName in abrvCountryNames)
			{
				if (searchString.Contains(countryName))
				{
					searchString = searchString.Replace(countryName, "");
					return countryName;
				}
			}

			return "";
		}

		public static List<String> ExtractColoursFromSearchString(ref String searchString)
		{
			ColourRepository colourRepository = new ColourRepository();
			List<String> colourList = colourRepository.FindAllColours().Select(u => u.Colour1).ToList();
			List<String> returnList = new List<string>();
			foreach (var color in colourList)
			{
				if (searchString.Contains(color))
				{
					returnList.Add(color);
					searchString = searchString.Replace(color, "");
				}
			}
			return returnList;
		}

		public static List<String> ExtractCategoriesFromSearchString(ref String searchString)
		{
			CategoryRepository categoryRepository = new CategoryRepository();
			List<String> categories = categoryRepository.FindAllCategories().Select(u => u.DisplayName).ToList();
			List<String> returnList = new List<string>();
			foreach (var category in categories)
			{
				if (searchString.Contains(category))
				{
					returnList.Add(category);
					searchString = searchString.Replace(category, "");
				}
			}
			return returnList;
		}

		public static List<String> ExtractWildCardsFromSearchString(ref String searchString)
		{
			List<String> splitString = searchString.Split(' ').ToList();
			List<String> returnList = new List<string>();
			foreach (var str in splitString)
			{
				if (str.Length > 1)
					returnList.Add(str);
			}

			return returnList;
		}

		public void BuildTextSearcher(String searchText)
		{
			OriginalSearchText = searchText;
			searchText = StripArticlesFromSearchString(searchText);
			CountryName = ExtractCountryFromSearchString(ref searchText);
			Dates = ExtractStampYearFromSearchString(ref searchText);
			FaceValue = ExtractStampValueFromSearchString(ref searchText, ref _isMajor);
			IsMajorCurrency = _isMajor;

			Colours = ExtractColoursFromSearchString(ref searchText);
			Categories = ExtractCategoriesFromSearchString(ref searchText);
			WildCards = ExtractWildCardsFromSearchString(ref searchText);
		}

		public SearchHit GetHit(Stamp stamp)
		{
			if (HitList.Where(u => u.Stamp == stamp).Count() > 0)
			{
				return HitList.Where(u => u.Stamp == stamp).SingleOrDefault();
			}
			else
			{
				SearchHit searchHit = new SearchHit();
				searchHit.Stamp = stamp;
				HitList.Add(searchHit);
				return searchHit;
			}
		}

		public void CalculateSearchHits(List<Stamp> searchResults)
		{
			foreach (var stamp in searchResults)
			{
				SearchHit hit = GetHit(stamp);
				hit.Hits++;
			}			
		}

		public void RunTextSearch()
		{
			HitList = new List<SearchHit>();
			StampRepository stampRepository = new StampRepository();

			//The obvious one will be an exact match on the display names
			List<Stamp> searchResults =
				stampRepository.FindAllStamps(Guid.Empty).Where(u => u.DisplayName.ToLower() == OriginalSearchText).ToList();

			CalculateSearchHits(searchResults);

			searchResults =
				stampRepository.FindAllStamps(Guid.Empty).Where(u => u.Country.Name.ToLower().Contains(CountryName)).ToList();

			CalculateSearchHits(searchResults);

			searchResults =
				stampRepository.FindAllStamps(Guid.Empty).Where(u => Categories.Contains(u.DisplayName.ToLower())).ToList();

			CalculateSearchHits(searchResults);

			searchResults =
				stampRepository.FindAllStamps(Guid.Empty).Where(u => Colours.Contains(u.Colour.Colour1.ToLower())).ToList();

			CalculateSearchHits(searchResults);

			searchResults =
				stampRepository.FindAllStamps(Guid.Empty).Where(u => WildCards.Contains(u.SubCategory.ToLower())).ToList();

			CalculateSearchHits(searchResults);

			Decimal dDecimal;
			if (IsMajorCurrency)
			{
				dDecimal = Decimal.Parse(FaceValue);
			}
			else
			{
				if (FaceValue.Length > 9)
				{
					FaceValue = "0." + FaceValue;
				}
				else
				{
					FaceValue = "0.0" + FaceValue;
				}

				dDecimal = Decimal.Parse(FaceValue);
			}

			searchResults =
				stampRepository.FindAllStamps(Guid.Empty).Where(u => u.FaceValue == dDecimal).ToList();

			CalculateSearchHits(searchResults);



		}
	}
}